#ifndef TRANSACTION_H
#define TRANSACTION_H
#include <memory>
#include <functional>
#include "Define.h"
#include "MetaObjectIO.h"
#include "ErrorCode.h"

namespace gitstore {

template<typename T>
struct has_getObject{
    template<typename U, typename U::ObjectAutoRecycle(U::*)()> struct HELPS;
    template<typename U> static char Test(HELPS<U, &U::getObject>*);
    template<typename U> static int Test(...);
    const static bool Has = sizeof(Test<T>(0)) == sizeof(char);
};

template<typename T>
struct has_getObject2{
//    template<typename U, typename U::ObjectAutoRecycle(U::*)()> struct HELPS;
    template<typename U, typename X =
             typename std::decay<decltype(std::declval<U>().getObject())>::type> static char Test(int);
    template<typename U> static int Test(...);
    const static bool Has = sizeof(Test<T>(0)) == sizeof(char);
};

template<typename FUNC> struct ServiceImpl;
//template<typename Ret, typename Class, typename...Args> struct Transaction;
template <typename Ret, typename Controller, typename...Args>
struct ServiceImpl<Ret(Controller::*)(Args...)> {
    using functype = Ret(Controller::*)(Args...);
    static Ret run(functype func, Args...args) {
        static_assert (std::is_same<Ret, ErrorStatus>::value, "Result Must be ErrorStatus");
//        static_assert (std::is_same<Args, ErrorStatus>::value, "test");
        auto controller = std::make_unique<Controller>();
        Ret res = (controller.get()->*func)(args...);
        return res;
    }

    static Ret run(functype func, Controller* controller, Args...args) {
        static_assert (std::is_same<Ret, ErrorStatus>::value, "Result Must be ErrorStatus");
//        static_assert (std::is_same<Args, ErrorStatus>::value, "test");
        Ret res = (controller->*func)(args...);
        return res;
    }

    template<typename ObjectPool>
    static Ret run(functype func, ObjectPool pool, Args...args) {
        static_assert (std::is_same<Ret, ErrorStatus>::value, "Result Must be ErrorStatus");
        static_assert (has_getObject<typename decltype(pool)::element_type>::Has, "Has No GetObject Function");
        static_assert (std::is_same<typename decltype(pool->getObject())::element_type, Controller>::value, "Controller Not Match");
//        static_assert (std:, )
//        static_assert (std::is_same<Args, ErrorStatus>::value, "test");
        Ret res = (pool->getObject().get()->*func)(args...);
        return res;
    }

};


#define RUN_SERVICE(func, args...) ServiceImpl<decltype(func)>::run(func, args)
}
#endif // TRANSACTION_H
